package com.sharing.aop;

import com.sharing.common.Result;
import com.sharing.domain.User;
import com.sharing.mapper.UserMapper;
import com.sharing.util.FunnelRateLimiter;
import com.sharing.util.ThreadLocalStorage;
import com.sun.org.apache.regexp.internal.RETest;
import com.sun.org.apache.xml.internal.utils.Hashtree2Node;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;

/**
 * @author MingTian
 * @version 1.0
 * @description TODO
 * @date 2023/7/18 15:36
 */
@Aspect
@Component
public class FunnelRateLimiterAop {
    @Autowired
    private UserMapper userMapper;

    public static HashMap<String, FunnelRateLimiter> funnels = new HashMap<>();

    @Pointcut("execution(* com.sharing.controller.*Controller.*(..))")
    private void pt(){}

    /**
     * 通过环绕通知的AOP对控制层方法加强，
     * 在执行控制层方法之前，需要通过漏斗算法判断该请求是否被允许
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("pt()")
    public Object funnelRateLimiterAround(ProceedingJoinPoint pjp) throws Throwable {
        // 获取当前登录用户
        User loginUser = ThreadLocalStorage.getUser();
        if (loginUser == null) {
            synchronized (this) {
                if (loginUser == null) {
                    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                    loginUser = userMapper.selectUserByUserName(authentication.getName());
                    ThreadLocalStorage.setUser(loginUser);
                }
            }
        }

        // 获取请求路径
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = null;
        if (requestAttributes instanceof ServletRequestAttributes){
            request =  ((ServletRequestAttributes) requestAttributes).getRequest();
        }

        String route = request.getRequestURL().toString();

        // 拼接key
        String key = loginUser.getId() + route;

        if (!funnels.containsKey(key)) {
            // 对该用户的此次行为创建限制器
            FunnelRateLimiter funnelRateLimiter = new FunnelRateLimiter(10, 2);
            funnels.put(key, funnelRateLimiter);

            boolean result = funnelRateLimiter.watering(1);
            if (result) {
                // 该请求可以访问
                Object o = pjp.proceed();
                return o;
            } else {
                // 该请求被限制住，不可访问
                return new Result<>(1, "请求频繁，请稍后尝试");
            }
        } else {
            // 该用户已经访问过该请求
            FunnelRateLimiter funnelRateLimiter = funnels.get(key);
            boolean result = funnelRateLimiter.watering(1);
            if (result) {
                // 该请求可以访问
                Object o = pjp.proceed();
                return o;
            } else {
                // 该请求被限制住，不可访问
                return new Result<>(1, "请求频繁，请稍后尝试");
            }
        }
    }
}

// 创建基于redis和AOP的新注解来实现请求限流
// 新注解是用于controller层的方法上的
//public class NoRepeatSubmitAspect {
//
//    private static final Logger logger = LoggerFactory.getLogger(NoRepeatSubmitAspect.class);
//
//    @Autowired
//    private JedisUtil jedisUtil;
//    @Autowired
//    UrlsConfig urlsConfig;
//
//    @Pointcut("@annotation(com.jd.bt.sscsign.common.aspect.NoRepeatSubmit)")
//    public void NoRepeatSubmitAspect(){
//    }
//
//    @Around("NoRepeatSubmitAspect()")
//    public Object arround(ProceedingJoinPoint pjp) {
//        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//        HttpServletRequest request = null;
//        if (requestAttributes instanceof ServletRequestAttributes){
//            request =  ((ServletRequestAttributes) requestAttributes).getRequest();
//        }
//        String token = request.getHeader("Authorization");
//        if (StringUtils.isEmpty(token)){
//            token = StringUtils.isEmpty(request.getHeader("contractId"))?request.getRemoteAddr():request.getHeader("contractId");
//        }
//        String key = token + "-" + request.getServletPath();
//        String resultKey = key + ":result";
//        String path = request.getServletPath();
//        try {
//            Signature sig = pjp.getSignature();
//            MethodSignature msig = null;
//            if (sig instanceof MethodSignature){
//                msig = (MethodSignature) sig;
//            }
//            Object target = pjp.getTarget();
//            Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
//            //获取注解信息
//            NoRepeatSubmit annotation = currentMethod.getAnnotation(NoRepeatSubmit.class);
//            // 如果缓存中有这个url视为重复提交
//            if (StringUtils.isEmpty(jedisUtil.get(key))) {
//                logger.info("未获取到缓存");
//                jedisUtil.set(key, "0",annotation.timeInterval());
//                Object o = null;
//                if(singleCrossPathCheck(path)){
//                    if (jedisUtil.get(resultKey)==null){
//                        jedisUtil.set(resultKey,"true",60);
//                        o = pjp.proceed();
//                        jedisUtil.delete(resultKey);
//                    }else {
//                        return ResultInfo.failedResultInfo(BaseConstants.PROCESS_IS_RUNNING_CODE,BaseConstants.PROCESS_IS_RUNNING_MSG);
//                    }
//                }else {
//                    o = pjp.proceed();
//                }
//                return o;
//            } else {
//                logger.error("重复提交,请求路径："+request.getServletPath());
//                return ResultInfo.failedResultInfo(BaseConstants.TOO_MANY_REQUEST_CODE,BaseConstants.TOO_MANY_REQUEST_MSG);
//            }
//        } catch (Throwable e) {
//            logger.error("{}验证重复提交时出现异常",request.getServletPath(),e);
//            if(singleCrossPathCheck(path)){
//                jedisUtil.delete(resultKey);
//            }
//            if (e instanceof SSCSignException){
//                SSCSignException exception = (SSCSignException) e;
//                throw exception;
//            }
//            return ResultInfo.failedResultInfo(BaseConstants.UNKNOWN_ERROR_CODE,BaseConstants.UNKNOWN_ERROR_MSG);
//        }
//    }
//
//    private boolean singleCrossPathCheck(String path){
//        //限制用户单线程访问的请求路径检查
//        List<String> singleCrossPaths = urlsConfig.getSingleCrossPaths();
//        return singleCrossPaths.contains(path);
//    }
//}
